home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Source / MiscKit / MiscStringUNIX.m < prev    next >
Encoding:
Text File  |  1995-07-11  |  8.5 KB  |  307 lines

  1. //
  2. //    MiscStringUNIX.m
  3. //        Written by Don Yacktman Copyright (c) 1993 by Don Yacktman.
  4. //                Version 1.95  All rights reserved.
  5. //        This notice may not be removed from this source code.
  6. //
  7. //    This object is included in the MiscKit by permission from the author
  8. //    and its use is governed by the MiscKit license, found in the file
  9. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  10. //    for a list of all applicable permissions and restrictions.
  11. //    
  12.  
  13. #import <misckit/MiscString.h>
  14. #include <pwd.h>
  15.  
  16. static char theMiscPathSeparator = '/';
  17. static char theMiscExtensionSeparator = '.';
  18.  
  19. @implementation MiscString(Unix)
  20.  
  21. // This category includes methods to support various UNIX features,
  22. // such as file/path name parsing and encryption of passwords.
  23.  
  24. + setPathSeparator:(char)c { theMiscPathSeparator = c; return self; }
  25. + setExtensionSeparator:(char)c { theMiscExtensionSeparator = c; return self; }
  26. + (char)extensionSeparator { return theMiscExtensionSeparator; }
  27. + (char)pathSeparator { return theMiscPathSeparator; }
  28.  
  29. - encrypt:salt
  30. {    // encrypt as a UNIX password using the MiscString "salt" as the salt...
  31.     // see crypt(3) for more info
  32.     // The cast prevents a warning:  -stringValue returns a const char *.
  33.     // Assuming crypt() doesn't change the salt, the cast is OK.
  34.     char *strv;
  35.     if ([salt respondsTo:@selector(stringValue)])
  36.         strv = (char *)[salt stringValue];
  37.     else return nil;
  38.     if (!(buffer && strv)) return nil;
  39.     if (!length || !strlen(strv)) return nil;
  40.     return [[[self class] alloc] initString:crypt(buffer, strv)];
  41. }
  42.  
  43. - fileNameFromZone:(NXZone *)zone
  44. {
  45.     return [self extractPart:MISC_STRING_LAST
  46.                 useAsDelimiter:theMiscPathSeparator
  47.                 caseSensitive:YES fromZone:zone];
  48. }
  49.  
  50. - fileName
  51. {
  52.     return [self fileNameFromZone:[self zone]];
  53. }
  54.  
  55. - pathNameFromZone:(NXZone *)zone
  56. {
  57.     id temp = [self left:[self rspotOf:theMiscPathSeparator] fromZone:zone];
  58.     if (temp) return temp;
  59.     return [[self class] new];
  60. }
  61.  
  62. - pathName
  63. {
  64.     return [self pathNameFromZone:[self zone]];
  65. }
  66.  
  67. - fileExtensionFromZone:(NXZone *)zone
  68. {
  69.     id temp = [self fileNameFromZone:[self zone]];
  70.     id extension = [temp extractPart:MISC_STRING_LAST
  71.                 useAsDelimiter:theMiscExtensionSeparator
  72.                 caseSensitive:YES fromZone:zone];
  73.     if ([temp isEqual:extension] ||
  74.             (0 == [temp rspotOf:theMiscExtensionSeparator
  75.             occurrenceNum:0 caseSensitive:YES]))
  76.         [extension setStringValue:""];
  77.     [temp free];
  78.     return extension;
  79. }
  80.  
  81. - fileExtension
  82. {
  83.     return [self fileExtensionFromZone:[self zone]];
  84. }
  85.  
  86. - fileBasenameFromZone:(NXZone *)zone
  87. {
  88.     id base, temp = [self fileNameFromZone:[self zone]];
  89.     int right = [temp rspotOf:theMiscExtensionSeparator
  90.             occurrenceNum:0 caseSensitive:YES] - 1;
  91.     if (right < 0) right = length - 1;
  92.     base = [temp midFrom:0 to:right fromZone:zone];
  93.     [temp free];
  94.     return (base ? base : [[self class] new]);
  95. }
  96.  
  97. - fileBasename
  98. {
  99.     return [self fileBasenameFromZone:[self zone]];
  100. }
  101.  
  102. - addExtensionIfNeeded:(const char *)aString
  103. {
  104.     id    ourExtension;
  105.     
  106.     if (!aString) return nil;  // maybe we should _strip_ extensions here
  107.     
  108.     ourExtension = [self fileExtension];
  109.  
  110.     if ( [ourExtension length] == 0 ||
  111.         [ourExtension cmp:aString] != 0 ) {
  112.         if ([self charAt:(length - 1)] != theMiscExtensionSeparator)
  113.             [self addChar:theMiscExtensionSeparator];
  114.         [self cat:aString];
  115.     }    
  116.     [ourExtension free];
  117.     return self;
  118. }
  119.  
  120. // June 1995: Carl Lindberg
  121. // Rewrote -replaceHomeWithTilde and -replaceTildeWithHome because they
  122. //   a) had bad problems when user was root
  123. //   b) thought all users home dirs were in the same directory, and
  124. //   c) had problems when one username was a prefix of another
  125. //       (e.g., "tom" and "tomsmith").
  126. // It was rather bad code, in retrospect. *Sigh*  I hope I thought
  127. // of everything this time.
  128.  
  129. - replaceHomeWithTilde
  130. {
  131.     id homestr = [[self class] newWithString:NXHomeDirectory()];
  132.     char rootdir[2] = {theMiscPathSeparator,0};
  133.  
  134.     // Make sure user isn't root, and also be careful not to
  135.     // "/Users/tom" is not taken to be a match when the current
  136.     // string is "/Users/tomsmith/Apps" (that's what the third
  137.     // condition checks)
  138.     if (![self compareTo:homestr n:[homestr length]] &&
  139.        ([homestr cmp:rootdir]) &&
  140.        (([self charAt:[homestr length]] == theMiscPathSeparator) ||
  141.         ([homestr length] == [self length])))
  142.     {
  143.         [self replaceFrom:0 length:[homestr length] withChar:'~'];
  144.     }
  145.     else {   // see if we can match a user's home dir, and if so
  146.              // translate to "~username/subdir"
  147.       struct passwd *userEntry;
  148.       
  149.       setpwent();
  150.       while (userEntry = getpwent()) {
  151.         [homestr setStringValue:userEntry->pw_dir];
  152.         if (([homestr length]) &&
  153.             ([homestr cmp:rootdir])  &&
  154.             (![self compareTo:homestr n:[homestr length]]) &&
  155.             (([self charAt:[homestr length]] == theMiscPathSeparator) ||
  156.              ([homestr length] == [self length])))
  157.         {
  158.           [self replaceFrom:0 length:[homestr length] with:"~"];
  159.           [self insert:userEntry->pw_name at:1];
  160.           break;
  161.         }
  162.       }
  163.       endpwent();
  164.     }
  165.     [homestr free];
  166.     return self;
  167. }
  168.  
  169. - replaceTildeWithHome
  170. {
  171.     id home;
  172.     char rootdir[2] = {theMiscPathSeparator,0};
  173.  
  174.     if (!buffer || (buffer[0] != '~')) return self;
  175.  
  176.     home = [[self class] newWithString:NXHomeDirectory()];
  177.  
  178.     if (length == 1) {                 //string is just "~"
  179.       [self takeStringValueFrom:home];
  180.     }
  181.     else if (buffer[1] == theMiscPathSeparator) { //starts with "~/"
  182.       if (![home cmp:rootdir])         // root--take out "~"
  183.         [self removeFrom:0 to:0];
  184.       else
  185.         [self replaceFrom:0 length:1 withString:home];
  186.     }
  187.     else {        // a "~username" variety; check if username exists
  188.       int spot = [self spotOf:theMiscPathSeparator];
  189.       id username;
  190.       struct passwd *userEntry;
  191.       if (spot == -1) spot = length;
  192.  
  193.       username = [self midFrom:1 to:spot-1];
  194.       userEntry = getpwnam([username stringValue]);
  195.       if (userEntry && userEntry->pw_dir) {
  196.         [self replaceFrom:0 to:spot-1 with:userEntry->pw_dir];
  197.       }
  198.       [username free];
  199.     }
  200.     [home free];
  201.     return self;
  202. }
  203.  
  204. - (BOOL)isRelativePath
  205. // Returns YES if the path is non-empty and does NOT begin with pathSeparator.
  206. {
  207.     id tempPath = [self pathName];
  208.     if ([tempPath length] && ([tempPath charAt:0] != theMiscPathSeparator)) {
  209.         [tempPath free];
  210.         return YES;
  211.     }
  212.     [tempPath free];
  213.     return NO;
  214. }
  215.  
  216. - (BOOL)isAbsolutePath
  217. // Returns YES if the path is non-empty and DOES begin with pathSeparator.
  218. {
  219.     id tempPath = [self pathName];
  220.     if ([tempPath length] && ([tempPath charAt:0] == theMiscPathSeparator)) {
  221.         [tempPath free];
  222.         return YES;
  223.     }
  224.     [tempPath free];
  225.     return NO;
  226. }
  227.  
  228. - (BOOL)doesExistInFileSystem
  229. // Returns YES if the a file exists at our path, and is visible to the user 
  230. // id of the process.  A NO can mean any number of things, but a YES 
  231. // definitely indicates that the file is there and visible.
  232. {
  233.     struct stat statBuff;
  234.     if (!buffer) return NO;
  235.     if (stat([self stringValue], &statBuff) == -1) return NO;
  236.     return YES;
  237. }
  238.  
  239. - (BOOL)isFileOfType:(MiscFileType)fileType
  240. // Returns YES if the named file exists, and is visible to the user id of
  241. // the process and it is a file of type fileType.  A NO can mean any number
  242. // of things,  but a YES definitely indicates that the file is there and
  243. // visible and of the fileType type.  
  244. {
  245.     struct stat statBuff;
  246.     if (!buffer) return NO;
  247.     if (stat([self stringValue], &statBuff) == -1) return NO;
  248.     return ((statBuff.st_mode & fileType) == fileType);
  249. }
  250.  
  251. - pathComponentAt:(int)index
  252. {
  253.     if ((index < 0) || (index >= [self numberOfPathComponents]))
  254.         return [[self class] newWithString:""];
  255.     return [self extractPart:([self isAbsolutePath] ? (index + 1) : index)
  256.                 useAsDelimiter:theMiscPathSeparator
  257.                 caseSensitive:YES fromZone:[self zone]];
  258. }
  259.  
  260. - (int)numberOfPathComponents
  261. {
  262.     return ([self numOfChar:theMiscPathSeparator] -
  263.             ([self isAbsolutePath] ? 1 : 0));    
  264. }
  265.  
  266. /*
  267.  * Modified [-setDirectory:file:] and [-initDirectory:file:] to use the
  268.  * official misc path separator, rather than a hard-coded '/'. BJM 7/9/94
  269.  */
  270. - setDirectory:(const char *)dir file:(const char *)file
  271. {
  272.     return [self setFromFormat:"%s%c%s", dir, theMiscPathSeparator, file];
  273. }
  274.  
  275. - initDirectory:(const char *)dir file:(const char *)file
  276. {
  277.     return [self initFromFormat:"%s%c%s", dir, theMiscPathSeparator, file];
  278. }
  279.  
  280. - (int)system
  281. {
  282.     return system([self stringValue]);
  283. }
  284.  
  285. - loadFromFile:(const char *)fileName
  286. {
  287.     int theFile;
  288.     struct stat fileInfo;
  289.  
  290.     if (!fileName || stat(fileName, &fileInfo) ||
  291.             !(theFile = open(fileName, O_RDONLY))) { 
  292.         return nil;
  293.     }
  294.     if (fileInfo.st_size) {                     
  295.         [self allocateBuffer:fileInfo.st_size]; // make sure we're big enough
  296.         if (fileInfo.st_size != read(theFile, buffer, fileInfo.st_size)) {
  297.             close(theFile);
  298.             return nil;
  299.         }
  300.     }
  301.     close(theFile);
  302.     [self recalcLength];
  303.     return self;
  304. }
  305.  
  306. @end
  307.